package com.xiaoxin.experience.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class DateUtil
{

    public static final String YMD = "yyyyMMdd";

    public static final String HMS = "HHmmss";

    public static final String YM = "yyyy-MM";

    public static final String YMD_DASH = "yyyy-MM-dd";

    public static final String YMD_DOT = "yyyy.MM.dd";

    public static final String YMDH = "yyyy-MM-dd HH";

    public static final String YMDHM = "yyyy-MM-dd HH:mm";

    public static final String YMDHMS = "yyyyMMddHHmmss";

    public static final String YMDHMS_MS = "yyyyMMddHHmmssSSS";

    public static final String YMDHMS_STD = "yyyy-MM-dd HH:mm:ss";

    public static final String HMS_STD = "HH:mm:ss";

    public static final String YMDHMS_STD_MS = "yyyy-MM-dd HH:mm:ss.SSS";

    /**
     * 默认时间戳 值：19700101000000
     */
    public static final String DEFAULT_TIMESTAMP = "19700101000000";

    public static final long ONE_YEAR_MILLIS = 365 * 24 * 3600 * 1000L;

    /**
     * 获取当前时间格式化为yyyyMMdd
     *
     * @return 时间格式化字符串
     */
    public static String nowYmd()
    {
        return now(YMD);
    }

    /**
     * 获取当前时间格式化为yyyyMMddHHmmss
     *
     * @return 时间格式化字符串
     */
    public static String nowYmdHms()
    {
        return now(YMDHMS);
    }

    /**
     * 获取当前时间格式化为yyyy-MM-dd HH:mm:ss
     *
     * @return 时间格式化字符串
     */
    public static String nowYmdHmsStd()
    {
        return now(YMDHMS_STD);
    }

    /**
     * 获取当前时间格式化为yyyyMMddHHmmss
     *
     * @return 时间格式化字符串
     */
    public static String now(String format)
    {
        return formatTime(new Date(), format);
    }

    /**
     * 格式化指定时间
     *
     * @return 时间格式化字符串
     */
    public static String formatTime(Date date, String format)
    {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.format(date);
    }

    public static String formatTimeStd(long time)
    {
        Date date = new Date(time);
        return formatTime(date,YMDHMS_STD);
    }

    /**
     * 将字符串转换成日期长整形 参数：time，String，日期字符串 pattern, String, 解析的格式 返回：long，日期长整形
     *
     * @param time    时间
     * @param pattern 政则表达式
     * @return long
     */
    public static long timeStr2Long(String time, String pattern)
    {
        return timeStr2Date(time, pattern).getTime();
    }

    public static String str2strDate(String dateStr, String basePatten, String convertPatten)
    {
        if (StringUtils.isBlank(dateStr))
        {
            return "";
        }
        else
        {
            return formatTime(timeStr2Date(dateStr, basePatten), convertPatten);
        }
    }

    /**
     * 将字符串转换成日期形 参数：time，String，日期字符串 pattern, String, 解析的格式 返回：Date，日期形
     *
     * @param time    时间
     * @param pattern 政则表达式
     * @return Date
     */
    public static Date timeStr2Date(String time, String pattern)
    {
        if (time == null)
        {
            throw new IllegalArgumentException("time parameter can not be null");
        }
        if (pattern == null)
        {
            throw new IllegalArgumentException("pattern parameter can not be null");
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        try
        {
            return sdf.parse(time);
        }
        catch (ParseException e)
        {
            throw new IllegalArgumentException("using [" + pattern + "] parse [" + time + "] failed");
        }
    }

    public static String getNowWeekBegin()
    {
        int dayPlus;
        Calendar cd = Calendar.getInstance();
        // 获得今天是一周的第几天，星期日是第一天，星期二是第二天......
        int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == 1)
        {
            dayPlus = 0;
        }
        else
        {
            dayPlus = 1 - dayOfWeek;
        }
        GregorianCalendar currentDate = new GregorianCalendar();
        currentDate.add(GregorianCalendar.DATE, dayPlus);
        Date sunday = currentDate.getTime();
        return formatTime(sunday, YMD_DASH);
    }

    public static String getNowWeekEnd()
    {
        int dayPlus;
        Calendar cd = Calendar.getInstance();
        // 获得今天是一周的第几天，星期日是第一天，星期二是第二天......
        int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == 7)
        {
            dayPlus = 0;
        }
        else
        {
            dayPlus = 7 - dayOfWeek;
        }
        GregorianCalendar currentDate = new GregorianCalendar();
        currentDate.add(GregorianCalendar.DATE, dayPlus);
        Date saturday = currentDate.getTime();
        return formatTime(saturday, YMD_DASH);
    }

    /**
     * 根据日期字符串判断当月第几周
     */
    public static int getMonthWeek(String dateTime)
        throws Exception
    {
        SimpleDateFormat sdf = new SimpleDateFormat(YMD_DASH);
        Date date = sdf.parse(dateTime);
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.SUNDAY);
        calendar.setTime(date);
        // 第几周
        int week = calendar.get(Calendar.WEEK_OF_MONTH);
        // 第几天，从周日开始
        // int day = calendar.get(Calendar.DAY_OF_WEEK);
        return week;
    }

    public static long getBetweenDays(Date beginDate, Date endDate)
    {
        long beginTime = beginDate.getTime();
        long endTime = endDate.getTime();
        return (long)Math.ceil((endTime - beginTime) / (1000 * 60 * 60 * 24.0));
    }

    public static long getDuration(String begin, String end)
    {
        return getDuration(begin, end, YMDHMS_STD);
    }

    public static long getDuration(String begin, String end, String pattern)
    {
        Date beginTime = timeStr2Date(begin, pattern);
        Date endTime = timeStr2Date(end, pattern);
        return (long)Math.ceil((endTime.getTime() - beginTime.getTime()) / 1000d);
    }

    public static String getYesterdayDate(String format)
    {
        Calendar cd = Calendar.getInstance();
        cd.add(Calendar.DATE, -1);
        Date yesterday = cd.getTime();
        return formatTime(yesterday, format);
    }

    /**
     * <不同时区时间转换>
     *
     * @param sourceDate     源日期时间
     * @param format         转换格式
     * @param sourceTimeZone 原时区
     * @param targetTimeZone 目标时区
     * @return 目标时间
     * @see [类、类#方法、类#成员]
     */
    public static String transDateBetweenTimeZone(String sourceDate, String format, TimeZone sourceTimeZone,
        TimeZone targetTimeZone)
    {
        return transDateBetweenTimeZone(timeStr2Date(sourceDate, format), format, sourceTimeZone, targetTimeZone);
    }

    public static String transDateBetweenTimeZone(Date sourceDate, String format, TimeZone sourceTimeZone,
        TimeZone targetTimeZone)
    {
        long targetTime = sourceDate.getTime() - sourceTimeZone.getRawOffset() + targetTimeZone.getRawOffset();
        return formatTime(new Date(targetTime), format);
    }

    public static Calendar fromDateStr(String dateStr, String format)
    {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(timeStr2Date(dateStr, format));
        return calendar;
    }

    public static List<Pair<String, String>> splitQueryDateFromTime(String beginTime, String endTime)
    {
        return splitQueryDateFromTime(beginTime, endTime, YMDHMS_STD);
    }

    public static List<Pair<String, String>> splitQueryDateFromTime(String beginTime, String endTime, String format)
    {
        Calendar bCalendar = fromDateStr(beginTime, format);
        Calendar eCalendar = fromDateStr(endTime, format);

        if (eCalendar.getTimeInMillis() - bCalendar.getTimeInMillis() > ONE_YEAR_MILLIS)
        {
            throw new IllegalArgumentException("time span must less than one year.");
        }

        List<Pair<String, String>> timeSpanList = new ArrayList<>();

        while (bCalendar.before(eCalendar))
        {
            bCalendar.set(Calendar.HOUR_OF_DAY, 23);
            bCalendar.set(Calendar.MINUTE, 59);
            bCalendar.set(Calendar.SECOND, 59);

            if (bCalendar.before(eCalendar))
            {
                timeSpanList.add(Pair.of(beginTime, formatTime(bCalendar.getTime(), format)));

                bCalendar.add(Calendar.DATE, 1);
                bCalendar.set(Calendar.HOUR_OF_DAY, 0);
                bCalendar.set(Calendar.MINUTE, 0);
                bCalendar.set(Calendar.SECOND, 0);
                beginTime = formatTime(bCalendar.getTime(), format);
            }
            else
            {
                timeSpanList.add(Pair.of(beginTime, endTime));
                break;
            }
        }

        return timeSpanList;
    }
}
